﻿/*
 *\logger.h
 *\brief 日记模块
 */
 
#ifndef  __logger_H__
#define  __logger_H__

#include <string> 
#include <fstream>
#include <iostream>


using namespace std;
 
///
/// \brief 日志文件的类型
///
typedef enum log_rank {
   INFO,
   WARNING,
   LERROR,
   SENSOR_DATA,
   FATAL
}log_rank_t;
 
///
/// \brief 初始化日志文件
/// \param info_log_filename 信息文件的名字
/// \param warn_log_filename 警告文件的名字
/// \param error_log_filename 错误文件的名字
void initLogger(const std::string& info_log_filename,
                const std::string& warn_log_filename,
                const std::string& error_log_filename);
void initSensorDataLogger(const std::string& sensor_data_filename);
///
/// \brief 日志系统类
///
class Logger {
   friend void initLogger(const std::string& info_log_filename,
                           const std::string& warn_log_filename,
                           const std::string& erro_log_filename);
   friend void initSensorDataLogger(const std::string& sensor_data_filename);
public:
         //构造函数
   Logger(log_rank_t log_rank) : m_log_rank(log_rank) {}
   
   ~Logger();   
   ///
   /// \brief 写入日志信息之前先写入的源代码文件名, 行号, 函数名
   /// \param log_rank 日志的等级
   /// \param line 日志发生的行号
   /// \param function 日志发生的函数
   static std::ostream& start(log_rank_t log_rank,
                               const int line,
                               const std::string& function);
   static std::ostream& startSensor(log_rank_t log_rank);
   
private:
   ///
   /// \brief 根据等级获取相应的日志输出流
   ///
   static std::ostream& getStream(log_rank_t log_rank);
   
   static std::ofstream m_info_log_file;                   ///< 信息日子的输出流
   static std::ofstream m_warn_log_file;                  ///< 警告信息的输出流
   static std::ofstream m_error_log_file;                  ///< 错误信息的输出流
   static std::ofstream m_sensor_data_file;                  ///< 错误信息的输出流
   log_rank_t m_log_rank;                             ///< 日志的信息的等级
};
 
///
/// \brief 根据不同等级进行用不同的输出流进行读写
///
#define LOGSensor(log_rank)   \
Logger(log_rank).startSensor(log_rank)
///
/// \brief 根据不同等级进行用不同的输出流进行读写
///
#define LOG(log_rank)   \
Logger(log_rank).start(log_rank, __LINE__,__FUNCTION__)
 
///
/// \brief 利用日记进行检查的各种宏
///
#define CHECK(a)                                            \
   if(!(a)) {                                              \
       LOG(LERROR) << " CHECK failed " << endl              \
                   << #a << "= " << (a) << endl;          \
       abort();                                            \
   }                                                      \
 
#define CHECK_NOTNULL(a)                                    \
   if( NULL == (a)) {                                      \
       LOG(LERROR) << " CHECK_NOTNULL failed "              \
                   << #a << "== NULL " << endl;           \
       abort();                                            \
    }
 
#define CHECK_NULL(a)                                       \
   if( NULL != (a)) {                                      \
       LOG(LERROR) << " CHECK_NULL failed " << endl         \
                   << #a << "!= NULL " << endl;           \
       abort();                                            \
    }
 
 
#define CHECK_EQ(a, b)                                      \
   if(!((a) == (b))) {                                     \
       LOG(LERROR) << " CHECK_EQ failed "  << endl          \
                   << #a << "= " << (a) << endl           \
                   << #b << "= " << (b) << endl;          \
       abort();                                            \
    }
 
#define CHECK_NE(a, b)                                      \
   if(!((a) != (b))) {                                     \
       LOG(LERROR) << " CHECK_NE failed " << endl           \
                   << #a << "= " << (a) << endl           \
                   << #b << "= " << (b) << endl;          \
       abort();                                            \
    }
 
#define CHECK_LT(a, b)                                      \
   if(!((a) < (b))) {                                      \
       LOG(LERROR) << " CHECK_LT failed "                   \
                   << #a << "= " << (a) << endl           \
                   << #b << "= " << (b) << endl;          \
       abort();                                            \
    }
 
#define CHECK_GT(a, b)                                      \
   if(!((a) > (b))) {                                      \
       LOG(LERROR) << " CHECK_GT failed "  << endl          \
                  << #a <<" = " << (a) << endl            \
                   << #b << "= " << (b) << endl;          \
       abort();                                            \
    }
 
#define CHECK_LE(a, b)                                      \
   if(!((a) <= (b))) {                                     \
       LOG(LERROR) << " CHECK_LE failed "  << endl          \
                   << #a << "= " << (a) << endl           \
                   << #b << "= " << (b) << endl;          \
       abort();                                            \
    }
 
#define CHECK_GE(a, b)                                      \
   if(!((a) >= (b))) {                                     \
       LOG(LERROR) << " CHECK_GE failed "  << endl          \
                   << #a << " = "<< (a) << endl            \
                   << #b << "= " << (b) << endl;          \
       abort();                                            \
    }
 
#define CHECK_DOUBLE_EQ(a, b)                               \
   do {                                                    \
       CHECK_LE((a), (b)+0.000000000000001L);              \
       CHECK_GE((a), (b)-0.000000000000001L);              \
    }while (0)


#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <Windows.h>
#endif

#define TRACE _trace
#ifdef _DEBUG
#ifdef WIN32
bool inline _trace(const char *format, ...) {
    char msg[4096] = { 0 };				\
        // TCHAR buffer[1000] = { '\n' };
        va_list pArgList;					\
        va_start(pArgList, format);			\
        vsprintf_s(msg, format, pArgList);  \
        // wvsprintf(buffer, _T(format), argptr);
        va_end(pArgList);					\
        OutputDebugStringA(msg);			\
        // OutputDebugString(buffer);
        return true;
}
#else
#include <stdarg.h>
bool inline _trace(const char *format, ...) {
    char msg[4096] = { 0 };			\
    va_list pArgList;				\
    va_start(pArgList, format);			\
    vsnprintf(msg,2048, format, pArgList);             \
    va_end(pArgList);				\
    std::cout <<msg;		\
    return true;
}
#endif
#else
bool inline _trace(const char *format, ...){return true;}
#endif

#endif
